package com.leyou.search.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.domain.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.JsonUtils;
import com.leyou.dto.*;
import com.leyou.search.doc.Good;
import com.leyou.search.feignclient.ItemClient;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.service.IndexService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @version V1.0
 * @author: Ljxpa
 * @date: 2020/03/11 21:32
 * @description:
 */
@Service
public class IndexServiceImpl implements IndexService {

	@Autowired
	private ItemClient itemClient;
	@Autowired
	private GoodsRepository goodsRepository;

	@Override
	public void loadDoc() {
		//使用死循环，向item-service服务发起请求查询所有上架的spu
		int page = 1;
		while (true) {
			PageResult<SpuDto> spuDtoPageResult = this.itemClient.pageQuerySpu(null, true, page, 50);
			if(null == spuDtoPageResult){break;}
			page++;
			List<SpuDto> spuDtoList = spuDtoPageResult.getItems();
			List<Good> goodList = spuDtoList.stream()
					.map(spuDto -> this.buildGoods(spuDto))
					.collect(Collectors.toList());

			goodsRepository.saveAll(goodList);
		}
	}


	/**
	 * 将spuDto转换成符合索引库文档的的good对象
	 *
	 * @param spuDto spuDto对象
	 * @return good对象
	 */
	@Override
	public Good buildGoods(SpuDto spuDto) {
		//spuDto中的属性值赋值给Good中
		Good good = BeanHelper.copyProperties(spuDto, Good.class);
		//1,简单值直接赋值
		good.setCategoryId(spuDto.getCid3());//给good赋值第三级分类id
		good.setCreateTime(spuDto.getCreateTime().getTime()); //将spu创建时间转换成long类型值然后赋值给good中的createtime

		//2，给good赋值skus，这里skus为json格式的数组，每个sku需要id，title，image，price,搜索结果主要展示spu，每一个spu中可以切换小图查看部分sku信息，具体功能参考京东
		//将查询到的skuDto集合，转换成json格式的集合，集合中的每个元素只要id，title，image，price四个变量
		//2.1，调用item-service服务， 根据spuId查询该spu下所有的sku信息,
		List<SkuDTO> skuDTOList = itemClient.querySkuBySpuId(spuDto.getId());
		HashSet<Long> prices = new HashSet<>();//创建一个set集合用来保存sku的价格，然后赋值给good
		LinkedList<Map<String, Object>> skus = new LinkedList<Map<String, Object>>();//用来存放只有id，title，image，price，四个属性的集合，map看成一个对象

		skuDTOList.forEach(skuDTO -> {
			HashMap<String, Object> map = new HashMap<>();
			map.put("id", skuDTO.getId());//取id放到map中
			map.put("title", skuDTO.getTitle());//取title放map中
			map.put("image", StringUtils.substringBefore(skuDTO.getImages(), ","));//去所有图片中的第一张图片放到map中
			map.put("price", skuDTO.getPrice());//取价格放到map中
			prices.add(skuDTO.getPrice());//将价格放到一个set中，然后赋值给good
			skus.add(map);//将map添加到list集合中，操作完成后解析成json格式字符串，然后赋值给good
		});
		good.setSkus(JsonUtils.toString(skus));//设置skus
		good.setPrice(prices);//设置price

		//3，设置good中all变量，all变量中包含标题，分类（三级分类都包含在内），品牌，所有的搜索只会根据这个来
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append(spuDto.getName());//追加商品的名称
		//3.1,根据spu的三个分类id，查询对应的分类名称,然后将分类名称添加到stringbuffer中
		List<CategoryDto> categoryDtos = itemClient.queryCategoriesByCids(spuDto.getCategoryIds());
		String categoryName = spuDto.getCategoryName().replace('/', ' ');
		stringBuffer.append(categoryName);//添加分类名，三级分类都包含
		// stringBuffer.append(spuDto.getSubTitle());//添加卖点信息

		stringBuffer.append(spuDto.getBrandName());//追加品牌信息
		good.setAll(stringBuffer.toString());//设置All变量信息，


		//4，设置good中specs变量，该变量用来对搜索结果进行过滤。specs的格式为Map<String,Object>,string为可过滤参数名，object为可过滤参数值
		HashMap<String, Object> specs = new HashMap<>();
		//4.1查询该品类下所有可用来进行搜索的规格参数
		List<SpecParamDTO> searchingParamList = itemClient.querySearchingParamsCategoryId(spuDto.getCid3(), true);

		//4.2，查询出spuDetail
		SpuDetailDTO spuDetailDTO = itemClient.querySpuDetailBySpuId(spuDto.getId());

		//4.3，将spuDetail中的genericSpec转成map
		Map<Long, Object> genericMap = JsonUtils.nativeRead(spuDetailDTO.getGenericSpec(), new TypeReference<Map<Long, Object>>() {
		});
		//4.4，将specialSpec转成map
		Map<Long, List<Object>> specialMap = JsonUtils.nativeRead(spuDetailDTO.getSpecialSpec(), new TypeReference<Map<Long, List<Object>>>() {
		});
		//4.5遍历可搜索规格参数组
		if (!CollectionUtils.isEmpty(searchingParamList) && !CollectionUtils.isEmpty(genericMap) && !CollectionUtils.isEmpty(specialMap)) {
			for (SpecParamDTO specParamDTO : searchingParamList) {
				Long id = specParamDTO.getId();
				String name = specParamDTO.getName();
				Object result = null;//接收规格参数的值，由于规格参数有各种类型，这里使用object接收
				if (specParamDTO.getGeneric()) {
					//如果是通用属性
					result = genericMap.get(id);
				} else {
					//非通用属性,获取属性的值
					result = specialMap.get(id);
				}
				if (specParamDTO.getNumeric()) {
					//如果是数值类型，则进行分段
					result = chooseSegment(result, specParamDTO);
				}
				specs.put(name, result);
			}
			good.setSpecs(specs);
		}
		//good中变量全部转换好之后，返回
		return good;
	}

	/**
	 * 将数值类型的规格参数进行分段，
	 *
	 * @param value spu中对应规格的值
	 * @param p     spuDto
	 * @return 分段之后是字符串
	 */
	private String chooseSegment(Object value, SpecParamDTO p) {
		if (value == null || StringUtils.isBlank(value.toString())) {
			//规格参数值为null，或者为空，返回其它
			return "其它";
		}
		//将数值类型的值解析成double
		double val = parseDouble(value.toString());
		String result = "其它";
		// 保存数值段
		for (String segment : p.getSegments().split(",")) {
			String[] segs = segment.split("-");//segment保存格式为：   0-5,5-10,10-
			// 获取数值范围
			double begin = parseDouble(segs[0]);
			double end = Double.MAX_VALUE;
			if (segs.length == 2) {
				end = parseDouble(segs[1]);
			}
			// 判断是否在范围内
			if (val >= begin && val < end) {
				if (segs.length == 1) {
					result = segs[0] + p.getUnit() + "以上";
				} else if (begin == 0) {
					result = segs[1] + p.getUnit() + "以下";
				} else {
					result = segment + p.getUnit();//数值类型，但是无分段，，，，，，，，，，，，，，匿名
				}
				break;
			}
		}
		return result;
	}

	private double parseDouble(String str) {
		try {
			return Double.parseDouble(str);
		} catch (Exception e) {
			return 0;
		}
	}
}
